{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bond Class\n",
    "\n",
    "This tutorial is meant to illustrate some of the properties and functionality available within the `Bond` class. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports necessary packages and checks the version of molli.\n",
    "import molli as ml \n",
    "ml.aux.assert_molli_version_min(\"1.0a\")\n",
    "\n",
    "#Loads in the dendrobine molecule\n",
    "mol = ml.load(ml.files.benzene_mol2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each `Molecule` has a list of bonds in a defined order. Individual bonds can be retrieved in a fashion similar in how to retrieve an `Atom`:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)"
      ]
     },
     "execution_count": 112,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ex_bond1 = mol.get_bond(0)\n",
    "ex_bond1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bonds have quite a few important properties"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a1': {'element': C,\n",
       "  'isotope': None,\n",
       "  'label': 'C',\n",
       "  'atype': <AtomType.Aromatic: 2>,\n",
       "  'stereo': <AtomStereo.Unknown: 0>,\n",
       "  'geom': <AtomGeom.Unknown: 0>,\n",
       "  'formal_charge': 0,\n",
       "  'formal_spin': 0,\n",
       "  'attrib': {},\n",
       "  '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>},\n",
       " 'a2': {'element': C,\n",
       "  'isotope': None,\n",
       "  'label': 'C',\n",
       "  'atype': <AtomType.Aromatic: 2>,\n",
       "  'stereo': <AtomStereo.Unknown: 0>,\n",
       "  'geom': <AtomGeom.Unknown: 0>,\n",
       "  'formal_charge': 0,\n",
       "  'formal_spin': 0,\n",
       "  'attrib': {},\n",
       "  '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>},\n",
       " 'label': None,\n",
       " 'btype': <BondType.Aromatic: 20>,\n",
       " 'stereo': <BondStereo.Unknown: 0>,\n",
       " 'f_order': 1.0,\n",
       " 'attrib': {},\n",
       " '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>}"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ex_bond1.as_dict()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's an example of individual atoms of the bond can be quickly called upon "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0)"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This calls Atom 1 of the bond\n",
    "atom1 = ex_bond1.a1\n",
    "\n",
    "#This calls Atom2 of a bond\n",
    "atom2 = ex_bond1.a2\n",
    "atom2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An important note about bonds is that `a1` (atom 1) and `a2` (atom2) are somewhat arbitrary depending on how the molecule was constructed/read in. Another option that can be come useful when looking is using the modulus (%) operator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This finds the other atom a part of the bond\n",
    "other_atom = ex_bond1 % atom2\n",
    "\n",
    "#This checks if atom1 is equal to the other_atom\n",
    "atom1 == other_atom"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`molli` implements that functionality to find atoms connected other atoms quickly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0),\n",
       " Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0),\n",
       " Atom(element=H, isotope=None, label='H', formal_charge=0, formal_spin=0)]"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This finds the atoms also connected to atom2\n",
    "connected_atoms = [a for a in mol.connected_atoms(atom2)]\n",
    "connected_atoms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`molli` also implements functionality to find the bonds associated with other atoms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The number of bonds with Atom 2 = 3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0),\n",
       " Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0),\n",
       " Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)]"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_bonds_atom2 = mol.n_bonds_with_atom(atom2)\n",
    "print(f'The number of bonds with Atom 2 = {n_bonds_atom2}')\n",
    "\n",
    "bonds_from_atom = [b for b in mol.bonds_with_atom(atom2)]\n",
    "bonds_from_atom"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Bond Deletion\n",
    "\n",
    "Bonds can also be quickly deleted either through the direct deletion of atoms or bonds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "1     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "2     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "3     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "4     Bond(a1=4, a2=5, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "5     Bond(a1=5, a2=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "6     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "7     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "8     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "9     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "10    Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "11    Bond(a1=5, a2=11, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n"
     ]
    }
   ],
   "source": [
    "# Prints the index of the bond and the bond itself\n",
    "for i, b in enumerate(mol.bonds):\n",
    "    print(format(i, \"<5\"), b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Deleting an `Atom` will delete both the `Atom` and the bonds associated with that `Atom"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "1     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "2     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "3     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "4     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "5     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "6     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "7     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "8     Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n"
     ]
    }
   ],
   "source": [
    "# Deletes the first atom in the molecule\n",
    "mol.del_atom(0)\n",
    "\n",
    "# Prints the updated bond list\n",
    "for i, b in enumerate(mol.bonds):\n",
    "    print(format(i, \"<5\"), b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Deleting a `Bond` will ONLY delete the `Bond`` and still maintain the same number of atoms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The number of atoms before deleting a bond = 11\n",
      "The number of atoms after deleting a bond = 11\n",
      "0     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "1     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "2     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)\n",
      "3     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "4     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "5     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "6     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n",
      "7     Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)\n"
     ]
    }
   ],
   "source": [
    "print(f'The number of atoms before deleting a bond = {mol.n_atoms}')\n",
    "\n",
    "#This gets the first bond in the list\n",
    "ex_bond = mol.get_bond(0)\n",
    "\n",
    "# Deletes the first bond in the molecule\n",
    "mol.del_bond(ex_bond)\n",
    "print(f'The number of atoms after deleting a bond = {mol.n_atoms}')\n",
    "\n",
    "# Prints the updated bond list\n",
    "for i, b in enumerate(mol.bonds):\n",
    "    print(format(i, \"<5\"), b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Other Miscellaneous Properties of Bonds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Bond` coordinates can be retrieved as follows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-3.8438, -0.82  , -0.    ],\n",
       "       [-2.7152, -1.6396, -0.    ]])"
      ]
     },
     "execution_count": 121,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This gets the first bond in the list\n",
    "ex_bond = mol.get_bond(0)\n",
    "\n",
    "# These are the coordinates of the atoms attached to the bond\n",
    "mol.bond_coords(ex_bond)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `Bond` length can be retrieved as follows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.3948054057824697"
      ]
     },
     "execution_count": 122,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This gets the length of a bond\n",
    "mol.bond_length(ex_bond)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bonds can also be found using atoms and indexed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 123,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#This finds the bond whose atoms 5 and 11 are associated with the bond\n",
    "ex_bond = mol.lookup_bond(3, 9)\n",
    "\n",
    "#This finds the index of the bond found\n",
    "mol.index_bond(ex_bond)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The vector created by the bond can also be called"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.8793, -0.6386,  0.    ])"
      ]
     },
     "execution_count": 124,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mol.bond_vector(ex_bond)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Much like the `Atom` class, the `Bond` class allows for storage of arbitrary objects. Here is an example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Current attribute list for an Example Bond\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'List': [0, 1, 2],\n",
       " 'Tuple': ('a', 'b', 'c'),\n",
       " 'Dictionary': {'Data': (0.1, 0.2, 0.3)}}"
      ]
     },
     "execution_count": 125,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Gets the first bond\n",
    "ex_bond = mol.get_bond(0)\n",
    "\n",
    "print(f'Current attribute list for an Example Bond')\n",
    "ex_bond.attrib[\"List\"] = [0,1,2]\n",
    "ex_bond.attrib[\"Tuple\"] = ('a','b','c')\n",
    "ex_bond.attrib[\"Dictionary\"] = {\"Data\": (0.1, 0.2, 0.3)}\n",
    "\n",
    "ex_bond.attrib"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "dev-blake",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
